package util

import (
	"reflect"
	"sync"
	"time"
)

var (
	runAtMap   sync.Map
	runningMap sync.Map
)

func DoOnceIn(t time.Duration, f func() error) (err error) {
	now := time.Now().UnixMilli()
	key := reflect.ValueOf(f).Pointer()
	if a, ok := runAtMap.Load(key); ok {
		runAt := a.(int64)
		if now-runAt < t.Milliseconds() {
			return
		}
	}

	if a, ok := runningMap.Load(key); ok {
		running := a.(bool)
		if running {
			return
		}
	}

	runAtMap.Store(key, time.Now().UnixMilli())
	runningMap.Store(key, true)
	defer func() {
		runningMap.Delete(key)
	}()
	err = f()
	return
}
